package com.zealcomm.ivcscustomer.service

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color
import android.os.Bundle
import android.os.Handler
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.core.text.HtmlCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.zco.base.BaseManager
import com.zco.base.Constants
import com.zco.base.ServerCallback
import com.zco.base.annotations.StreamType
import com.zco.base.interfaces.VideoStatusChangeListener
import com.zco.ccs.annotations.InvitationProgressType
import com.zco.ccs.entity.IDCardAndBankImageBean
import com.zco.ccs.entity.IDCardAndBankInfo
import com.zco.ccs.entity.InvitationProgressBean
import com.zco.ivcs.customer.IvcsCustomerCallback
import com.zco.util.*
import com.zealcomm.annotations.CollectImageType
import com.zealcomm.commonui.base.ViewBindingFragment
import com.zealcomm.commonui.beans.MessageContent
import com.zealcomm.commonui.widget.RecyclerViewDivider
import com.zealcomm.ivcsagent.widget.RemoteVideoView
import com.zealcomm.ivcscustomer.R
import com.zealcomm.ivcscustomer.adapter.RobotMessageAdapter
import com.zealcomm.ivcscustomer.app.IvcsApplication
import com.zealcomm.ivcscustomer.app.IvcsApplication.Companion.attachRenderWithLabel
import com.zealcomm.ivcscustomer.app.IvcsApplication.Companion.detachRenderWithLabel
import com.zealcomm.ivcscustomer.app.IvcsApplication.Companion.eGLContext
import com.zealcomm.ivcscustomer.app.IvcsApplication.Companion.exitSession
import com.zealcomm.ivcscustomer.app.IvcsApplication.Companion.mute
import com.zealcomm.ivcscustomer.app.IvcsApplication.Companion.switchCamera
import com.zealcomm.ivcscustomer.app.IvcsApplication.Companion.unmute
import com.zealcomm.ivcscustomer.databinding.FragmentRoomBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.webrtc.EglRenderer
import org.webrtc.SurfaceViewRenderer
import java.io.File
import java.io.FileOutputStream

class RoomFragment : ViewBindingFragment<FragmentRoomBinding>() {

    private val robotMessages = mutableListOf<MessageContent>()
    var rendererHashMap = HashMap<String, SurfaceViewRenderer?>()
    private val remoteVideoViews = arrayListOf<RemoteVideoView>()
    private var isMute = false
    private var smallRendererHeight = 0
    private var screenWidth = 0
    private var screenHeight = 0
    // 是否改变过 AI 坐席形象
    private var changedAIAgent = false
    override fun onAttach(context: Context) {
        super.onAttach(context)
        holdingActivity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        screenWidth = PhoneUtil.getScreenWidth(activity)
        screenHeight = PhoneUtil.getScreenHeight(activity)
        initView()
        setListeners()
    }

    private fun initView() {
        binding?.smallRenderer?.init(eGLContext, null)
        binding?.smallRenderer?.setMirror(true)
        binding?.smallRenderer?.setEnableHardwareScaler(false)
        binding?.smallRenderer?.setZOrderMediaOverlay(true)
        if ((holdingActivity as MainActivity).onlyAudio){
            binding?.smallRenderer?.visibility = View.INVISIBLE
            binding?.ivAudio?.visibility = View.VISIBLE
        }else{
            binding?.smallRenderer?.visibility = View.VISIBLE
            binding?.ivAudio?.visibility = View.GONE
        }

        binding?.screenRenderer?.init(eGLContext, null)
        binding?.screenRenderer?.setEnableHardwareScaler(false)
        binding?.screenRenderer?.setZOrderMediaOverlay(true)

        binding?.rvRobot?.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
        binding?.rvRobot?.addItemDecoration(
            RecyclerViewDivider(
                requireContext(), LinearLayoutManager.VERTICAL,
                ConvertUtil.dp2px(10), Color.TRANSPARENT, true
            )
        )
        binding?.rvRobot?.adapter = RobotMessageAdapter(robotMessages)
        attachRenderWithLabel(BaseManager.LOCAL_RENDER, binding?.smallRenderer)
    }

    var mAgentCount = 0

    /**
     * @param status true : joins,false : leave
     */
    fun updateView(videoLabel: String, status: Boolean, videoWidth: Int, videoHeight: Int) {
        GlobalScope.launch(Dispatchers.Main) {
            if (status) {
                showAIChanging(videoLabel , false)
                binding?.ivRing?.visibility = View.GONE
                binding?.tvWaiting?.visibility = View.GONE
                binding?.ivMute?.visibility = View.VISIBLE
                binding?.ivCamera?.visibility = View.VISIBLE
                var rendererTemp: SurfaceViewRenderer? = null
                when {
                    videoLabel.contains(StreamType.AGENT) ||
                            videoLabel.contains(StreamType.AI) -> {
                        var remoteVideoView:RemoteVideoView? = null
                        if (videoLabel.contains(StreamType.AI)){
                            remoteVideoViews.forEach {
                                if (it.tag.toString().contains(StreamType.AI)){
                                    remoteVideoView = it
                                    // FIXME:目前没有两个 AI 坐席的情况且只能根据 流 是否改变来判断 AI 坐席是否在切换形象，所以这里先这么处理
                                    showAIAgentChangeView(it)
                                    return@forEach
                                }
                            }
                        }
                        if(remoteVideoView == null){
                            remoteVideoView = RemoteVideoView(requireContext())
                            showAIAgentChangeView(remoteVideoView!!)
                            remoteVideoView!!.init(eGLContext, null)
                            remoteVideoViews.add(remoteVideoView!!)
                            val layoutParams =
                                LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0)
                            layoutParams.weight = 1f
                            binding!!.llRemoteViewContainer.addView(remoteVideoView, layoutParams)
                        }
                        remoteVideoView!!.isOnlyAudio((holdingActivity as MainActivity).onlyAudio)
                        remoteVideoView!!.tag = videoLabel
                        rendererTemp = remoteVideoView!!.svrAgent
                        mAgentCount++
                    }
                    videoLabel.contains(StreamType.SCREEN) -> {
                        rendererTemp = binding?.screenRenderer
                        binding?.smallRenderer?.visibility = View.INVISIBLE
                        var params = rendererTemp?.layoutParams
                        if (null == params) {
                            params = ViewGroup.LayoutParams(videoWidth, videoHeight)
                        } else {
                            params.width = videoWidth
                            params.height = videoHeight
                        }
                        rendererTemp?.layoutParams = params
                        // 对 screenRenderer 进行缩放
                        IvcsUtil.getApplicableScale(
                            screenWidth,
                            screenHeight,
                            videoWidth,
                            videoHeight
                        ).let {
                            rendererTemp!!.scaleX = it
                            rendererTemp!!.scaleY = it
                        }

                        // 监听屏幕共享流尺寸的改变
                        IvcsApplication.ivcsCustomer!!.addVideoStatusChangeListener(
                            videoLabel,
                            object : VideoStatusChangeListener {
                                var oldWidth = 0
                                var oldHeight = 0
                                var hasChangeSize = false
                                override fun onSizeChange(width: Int, height: Int) {
                                    hasChangeSize = oldHeight != height || oldWidth != width
                                    oldHeight = height
                                    oldWidth = width
                                    if (hasChangeSize) {
                                        GlobalScope.launch(Dispatchers.Main) {
                                            binding?.screenRenderer?.let {
                                                var params = it.layoutParams
                                                if (null == params) {
                                                    params = ViewGroup.LayoutParams(width, height)
                                                } else {
                                                    params!!.width = width
                                                    params!!.height = height
                                                }
                                                it.layoutParams = params
                                                // 进行缩放
                                                IvcsUtil.getApplicableScale(
                                                    screenWidth,
                                                    screenHeight,
                                                    width,
                                                    height
                                                ).let { scale ->
                                                    it.scaleX = scale
                                                    it.scaleY = scale
                                                }
                                            }
                                        }
                                    }
                                }
                            })
                    }
                }
                rendererTemp?.let {
                    attachRenderWithLabel(videoLabel, rendererTemp)
                    rendererTemp?.visibility = View.VISIBLE
                    rendererHashMap[videoLabel] = rendererTemp
                    binding?.ivRing?.visibility = View.GONE
                    binding?.tvWaiting?.visibility = View.GONE
                }
            } else {
                releaseRemoteVideoView(videoLabel)
                // 只有接到对方挂断的时候才结束，不要没有视频流就结束
                // try2Quit(videoLabel)
            }
        }
    }

    private fun releaseRemoteVideoView(videoLabel: String) {
        rendererHashMap[videoLabel]?.let {
            detachRenderWithLabel(videoLabel, it)
            if (videoLabel == StreamType.SCREEN) {
                binding?.smallRenderer?.visibility = View.VISIBLE
            }
            rendererHashMap.remove(videoLabel)
            if (videoLabel.contains(StreamType.AGENT) || videoLabel.contains(StreamType.AI)) {
                mAgentCount--
            }
        }
        // 注意：由于有 remove 操作，这里不要改成 forEach 的形式
        for (i in 0 until remoteVideoViews.size) {
            if (remoteVideoViews[i].tag == videoLabel) {
                if (videoLabel.contains(StreamType.AI)){
                    changedAIAgent = true
                }
                binding?.llRemoteViewContainer?.removeView(remoteVideoViews[i])
                remoteVideoViews.removeAt(i)
                break
            }
        }
    }

    private fun showAIAgentChangeView(remoteVideoView: RemoteVideoView){
        // FIXME:如果第一个视频流是 AI ，再来视频流算作切换 AI Agent 形象
        if (changedAIAgent){
            LogUtil.d("AI 坐席切换视频")
            remoteVideoView!!.isChangingAI(true)
            Handler().postDelayed({remoteVideoView!!.isChangingAI(false)} , 500)
        }
    }

    override fun onDestroyView() {
        binding?.ivHangUp?.callOnClick()
        releaseAll()
        holdingActivity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        super.onDestroyView()
    }

    private fun releaseAll() {
        rendererHashMap.keys.forEach {
            detachRenderWithLabel(it, rendererHashMap[it])
        }
        rendererHashMap.clear()
        binding?.smallRenderer?.release()
        binding?.screenRenderer?.release()
    }

    private fun setListeners() {
        binding?.ivChat?.setOnClickListener {
            (holdingActivity as MainActivity).showChatRoom()
        }
        binding?.ivMute?.setOnClickListener {
            if (isMute) {
                unmute()
            } else {
                mute()
            }
            isMute = !isMute
            binding?.ivMute?.setImageResource(if (isMute) R.drawable.audio_closed else R.drawable.audio)
        }
        binding?.ivCamera?.setOnClickListener {
            switchCamera()
        }
        binding?.ivHangUp?.setOnClickListener {
            exitSession(object : IvcsCustomerCallback {
                override fun onSuccess() {
                    GlobalScope.launch(Dispatchers.Main) {
                        activity?.finish()
                    }
                }

                override fun onFailed(i: Int, s: String) {
                    showToast(s)
                }
            })
        }
        binding?.ivGuideBoxBack?.setOnClickListener {
            binding?.ivGuideBox?.visibility = View.GONE
            binding?.ivGuideBoxBack?.visibility = View.GONE
            binding?.ivHangUp?.visibility = View.VISIBLE
            binding?.ivMute?.visibility = View.VISIBLE
            binding?.smallRenderer?.visibility = View.VISIBLE
            var params = binding?.smallRenderer?.layoutParams as FrameLayout.LayoutParams
            params.height = smallRendererHeight
            params.width = ViewGroup.LayoutParams.WRAP_CONTENT
            params.setMargins(0, ConvertUtil.dp2px(50), 0, 0)
            binding?.smallRenderer?.layoutParams = params
            binding?.llRemoteViewContainer?.visibility = View.VISIBLE
            binding?.ivChat?.visibility = View.VISIBLE
        }
    }

    fun showHangOn() {
        binding?.ivRing?.visibility = View.VISIBLE
        binding?.ivRing?.setImageResource(R.mipmap.img_hang_on)
        binding?.ivCamera?.visibility = View.INVISIBLE
        binding?.ivMute?.visibility = View.INVISIBLE
    }

    fun showWaiting(invitationProgressBean: InvitationProgressBean) {
        if (rendererHashMap.keys.size > 1) {
            // 当会话中存在两人以上时不展示状态界面
            return
        }
        when (invitationProgressBean?.status) {
            InvitationProgressType.NOT_FOUND -> {
            }
            InvitationProgressType.WAITING -> {
                binding?.tvWaiting?.visibility = View.VISIBLE
                binding?.tvWaiting?.text = HtmlCompat.fromHtml(
                    "<font size=\"6\">当前共 <font size=\"10\" color=\"#FF7845\">" +
                            "${invitationProgressBean?.waitingNum}" +
                            "</font> 人等待中</font>\n<font size=\"6\">您排在第 <font size=\"10\" color=\"#FF7845\">" +
                            "${invitationProgressBean?.position}" +
                            "</font> 位</font>", HtmlCompat.FROM_HTML_MODE_COMPACT
                )
            }
            InvitationProgressType.CONNECTING -> {
                binding?.tvWaiting?.visibility = View.GONE
            }
        }
    }

    /**
     * 当座席端退出会话时有可能只有一条 quit 消息， 和三方会话中的 quit 无法区分，这里根据存在坐席的个数及是否在振铃或转接中进行处理
     */
    fun try2Quit(videoLabel: String?) {
        rendererHashMap[videoLabel]?.let {
            detachRenderWithLabel(videoLabel, it)
            it?.visibility = View.GONE
            if (videoLabel == StreamType.SCREEN) {
                binding?.smallRenderer?.visibility = View.VISIBLE
            }
            rendererHashMap.remove(videoLabel)
            if (videoLabel?.contains(StreamType.AGENT) == true ||
                videoLabel?.contains(StreamType.AI) == true
            ) {
                mAgentCount--
            }
        }
        if (mAgentCount <= 0 && binding?.ivRing?.visibility != View.VISIBLE) {
            activity?.finish()
        }
    }

    fun showGuideBox() {
        binding?.ivGuideBox?.visibility = View.VISIBLE
        binding?.ivGuideBoxBack?.visibility = View.VISIBLE
        binding?.ivHangUp?.visibility = View.GONE
        binding?.ivMute?.visibility = View.GONE
        binding?.llRemoteViewContainer?.visibility = View.GONE
        binding?.ivChat?.visibility = View.GONE
        var params = binding?.smallRenderer?.layoutParams as FrameLayout.LayoutParams
        if (params == null) {
            params = FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
            smallRendererHeight = binding!!.smallRenderer.height
        } else {
            if (smallRendererHeight == 0) {
                smallRendererHeight = params.height
            }
        }
        params.setMargins(0, 0, 0, 0)
        params.height = ViewGroup.LayoutParams.MATCH_PARENT
        params.width = ViewGroup.LayoutParams.MATCH_PARENT
        binding?.smallRenderer?.layoutParams = params
    }

    fun uploadCollectImage(info: Int) {
        binding?.smallRenderer?.addFrameListener(object : EglRenderer.FrameListener {
            override fun onFrame(bitmap: Bitmap?) {
                bitmap?.let {
                    GlobalScope.launch(Dispatchers.IO) {
                        val file = File(context!!.filesDir, "${System.currentTimeMillis()}.jpg")
                        val outputStream = FileOutputStream(file)
                        if (it.compress(Bitmap.CompressFormat.JPEG, 80, outputStream)) {
                            outputStream.flush()
                            outputStream.close()
                            var idCardAndBankInfo: IDCardAndBankImageBean? = null
                            when (info) {
                                CollectImageType.ID_CARD_FRONT -> {
                                    idCardAndBankInfo = IDCardAndBankInfo()
                                    idCardAndBankInfo.frontPhoto =
                                        Constants.BASE64_IMAGE_PREFIX + Base64Util.toBase64String(
                                            file
                                        )
                                }
                                CollectImageType.ID_CARD_BACK -> {
                                    idCardAndBankInfo = IDCardAndBankInfo()
                                    idCardAndBankInfo.backPhoto =
                                        Constants.BASE64_IMAGE_PREFIX + Base64Util.toBase64String(
                                            file
                                        )
                                }
                                CollectImageType.BANK -> {
                                    idCardAndBankInfo = IDCardAndBankInfo()
                                    idCardAndBankInfo.bankCardPhoto =
                                        Constants.BASE64_IMAGE_PREFIX + Base64Util.toBase64String(
                                            file
                                        )
                                }
                                CollectImageType.SELF -> {
                                    idCardAndBankInfo = IDCardAndBankInfo()
                                    idCardAndBankInfo.selfie =
                                        Constants.BASE64_IMAGE_PREFIX + Base64Util.toBase64String(
                                            file
                                        )
                                }
                            }
                            idCardAndBankInfo?.let {
                                IvcsApplication.updateIDCardAndBankImage(
                                    (holdingActivity as MainActivity).formId,
                                    it,
                                    object : ServerCallback<Any>() {
                                        override fun successResponse(result: String?) {
                                            (holdingActivity as MainActivity)?.let {
                                                it.submitUserInfo(it.formId)
                                            }
                                        }

                                        override fun failedResponse(result: String?) {
                                        }

                                    })
                            }
                        }
                    }
                }
            }

        }, 1.0f)
    }

    fun notifyRobotMessage(messageContent: MessageContent) {
        GlobalScope.launch(Dispatchers.Main) {
            robotMessages.add(messageContent)
            binding?.rvRobot?.adapter?.notifyDataSetChanged()
            val lastPosition =
                (binding?.rvRobot?.layoutManager as LinearLayoutManager).findLastVisibleItemPosition()
            if (lastPosition >= robotMessages.size - 2) {
                // 说明是最后两项可以滚动
                binding?.rvRobot?.scrollToPosition(robotMessages.size - 1)
            }
        }
    }

    fun showSubTitle(show: Boolean) {
        if (!show) {
            GlobalScope.launch(Dispatchers.Main) {
                robotMessages.clear()
                binding?.rvRobot?.adapter?.notifyDataSetChanged()
            }
        }
    }

    fun showSmallRenderer(show: Boolean) {
        if (show) {
            binding?.smallRenderer?.visibility = View.VISIBLE
        } else {
            binding?.smallRenderer?.visibility = View.INVISIBLE
        }
    }

    fun showAIChanging(videoLabel: String , show: Boolean){
        remoteVideoViews.forEach {
            if (videoLabel == it.tag){
                it.isChangingAI(show)
                return@forEach
            }
        }
    }

}